Code Generation

指令选择

树型 Tree pattern

Pasted image 20230517095357.png

最佳覆盖与最优覆盖

Pasted image 20230517095111.png

Maximal Munch 算法

动态规划算法

活跃分析

活跃分析(liveness analysis):编译器分析程序的中间表示,以确定哪些零食变量在同时被使用。如果一个变量的值将来还需要使用,则称这个变量是活跃(live)的。

控制流图

Pasted image 20230517101722.png

数据流方程

变量的活跃性沿着控制流图的各条边“流动”,决定每个变量的活跃范围是数据流(dataflow)问题的一种。

流图术语

活跃性计算

bool changed = false;
do {
	changed = false;
	// 如果一个变量属于 use[n],那么它在结点 n 是入口活跃的
	for (int i = 0; i < n; ++i) {
		for (auto x: use[i]) {
			changed |= PushLiveIn(i, x);
		}
	}
	// 如果一个变量在结点 n 是入口活跃的,那么它在所有属于 pred[n] 结点 m 中都是出口活跃的
	for (int i = 0; i < n; ++i) {
		for (auto x: pred[i]) {
			for (auto y: live_in[i]) {
				changed |= PushLiveOut(x, y);
			}
		}
	}
	// 如果一个变量在结点 n 是出口活跃的,而且不属于 def[n],则该变量在结点 n 是入口活跃的
	for (int i = 0; i < n; ++i) {
		for (auto x: live_out[i]) {
			if (find(def[i].begin(), def[i].end(), x) == def[i].end()) {
				changed |= PushLiveIn(i, x);
			}
		}
	}
} while(changed);

冲突图

Pasted image 20230517104758.png

寄存器分配

Abstract

寄存器分配的是根据冲突图,使用不同的颜色表示不同的寄存器进行染色,并避免冲突的算法过程。如果目标机器有 K 个寄存器,则可以用 K 种颜色进行着色。如果不存在 K 色着色,则必须将一部分变量和临时变量存放在存储器中,而不是寄存器中,这称为溢出 spilling。

简化着色问题

处理阶段

合并

如果在冲突图中,一条传送指令的源操作数和目的操作数对应的结点之间不存在边,那么可以删除这条传输指令,并将源操作数结点和目的操作数结点合并,同时合并两个结点对应的边。

但是合并引入新的结点可能会使得图在合并前是 K 色着色的,在合并后反而不是 K 色着色的了。所以需要引入安全的合并策略:Briggs 和 George。

Briggs 合并策略

如果合并结点 a 和 b 后产生的结点 ab 的高度数邻接结点个数少于 K,则 a 和 b 可以合并。

George 合并策略

如果对于 a 的每一个邻居 t,要么 t 与 b 已有冲突,要么 t 是低度数结点,则 a 和 b 可合并。

处理阶段

Pasted image 20230517140805.png